package daos

import (
	"errors"
	"github.com/6tail/lunar-go/calendar"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"reflect"
	"sanrenx.com/xyxf/app/models"
	"sanrenx.com/xyxf/app/models/column"
	"time"
)

/**
 * 用户
 * @Description:
 */
type UserDao struct {
	DB *gorm.DB
}

/**
 * @Description: 是否存在
 * @receiver dao
 * @param openid  小程序 openid
 * @param platform 小程序 平台
 * @return bool true:存在;false:不存在
 * @return error 异常信息
 */
func (dao *UserDao) ExitUserByOpenID(openid string, platform string) (bool, error) {
	var count int64
	if err := dao.DB.Table("user").
		Select("id").
		Where("openid = ?", openid).
		Where("platform = ?", platform).
		Count(&count).
		Error; err != nil && err != gorm.ErrRecordNotFound {
		return false, err
	}

	return count > 0, nil
}

/**
 * @Description: 是否存在
 * @receiver dao
 * @param openid  小程序 unionid
 * @param platform 小程序 平台
 * @return bool true:存在;false:不存在
 * @return error 异常信息
 */
func (dao *UserDao) ExitUserByUnionID(unionid string, platform string) (bool, error) {

	var count int64

	if err := dao.DB.Table("user").
		Select("id").
		Where("unionid = ?", unionid).
		Where("platform = ?", platform).
		Count(&count).
		Error; err != nil && err != gorm.ErrRecordNotFound {
		return false, err
	}

	return count > 0, nil
}

/**
 * @Description: 获取第一个匹配的记录，或创建一个具有给定条件的新记录
 * @receiver dao
 * @param whereMap 匹配条件
 * @param attrMap 附加内容
 * @return *models.UserNewbie 用户信息
 * @return error 异常信息
 */
func (dao *UserDao) FirstOrCreateUser(whereMap map[string]interface{}, attrMap map[string]interface{}) (*models.UserNewbie, error) {

	var data models.UserNewbie

	if err := dao.DB.Table("user").
		Where(whereMap).
		Attrs(attrMap).
		FirstOrCreate(&data).
		Error; err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}

	return &data, nil
}

/**
 * @Description: 更新修行数据
 * @receiver dao
 * @param uid 用户ID
 * @param column 字段
 * @param inc 字段值
 * @return error 异常信息
 */
func (dao *UserDao) SaveStdColumn(key int, uid uint64, val interface{}) error {
	//开启事务更新
	err := dao.DB.Transaction(func(tx *gorm.DB) error {
		//获取字段的更新模式
		columnKey, incType, err := column.GetStdIncMode(key)
		if err != nil {
			return err
		}

		//================== user_std =================//
		//检查构造统计数据
		var std models.UserStd
		if err := tx.Table("user_std").
			Where(map[string]interface{}{
				"user_id": uid,
			}).FirstOrCreate(&std).
			Error; err != nil {
			return err
		}

		//如果是字符串 代表是时间 赋值 = 1
		var incVal = val
		if _, ok := val.(string); ok {
			incVal = 1
		}
		//更新统计数据
		if err := tx.Table("user_std").
			Where(map[string]interface{}{
				"user_id": uid,
			}).UpdateColumn(columnKey, gorm.Expr(columnKey+" + ?", incVal)).
			Error; err != nil {
			return err
		}

		//================== user_std =================//

		//================== user_std_daily =================//
		//更新的字段值
		var updValue = val
		if incType == "inc" { //更新模式 true:累计；false:赋值
			updValue = gorm.Expr(columnKey+" + ?", val)
		}
		//检查构造日常数据
		var daily models.UserDaily
		cal := calendar.NewSolarFromDate(time.Now())
		if err := tx.Table("user_std_daily").
			Where(map[string]interface{}{
				"user_id": uid,
				"ymd":     cal.ToYmd(),
			}).FirstOrCreate(&daily).
			Error; err != nil {
			return err
		}

		//更新日常数据
		if err := tx.Table("user_std_daily").
			Where(map[string]interface{}{
				"user_id": uid,
				"ymd":     cal.ToYmd(),
			}).UpdateColumn(columnKey, updValue).
			Error; err != nil {
			return err
		}

		//================== user_std_daily =================//

		//================== user_std_log =================//
		//构造日志模型
		var log *models.UserStdLog
		log, err = column.GetStdModel(key, uid, val)
		if err != nil {
			return nil
		}

		//插入新纪录
		if err := tx.Create(log).
			Error; err != nil {
			return err
		}

		//================== user_std_log =================//
		return nil
	})

	return err
}

/**
 * @Description: 更新资产数据
 * @receiver dao
 * @param uid 用户ID
 * @param column 字段
 * @param inc 字段值
 * @return error 异常信息
 */
func (dao *UserDao) SaveValColumn(key int, uid uint64, owner interface{}) (vu models.VU, err error) {

	var (
		columnKey string //更新字段
		curNum    int    //当前数值
		incNum    int    //获得数值
	)

	//获取字段的更新模式
	if columnKey, incNum, err = column.GetValIncMode(key); err != nil {
		return
	}

	//开启事务更新
	err = dao.DB.Transaction(func(tx *gorm.DB) error {

		//================== user_val =================//
		//增加记录信息
		var data models.UserVal
		if err := tx.Table("user_val").
			Where(map[string]interface{}{
				"user_id": uid,
			}).FirstOrCreate(&data).
			Error; err != nil {
			return err
		}

		//=======校验当前数值和增减数值 确认是否足量======//
		//动态获取 数值
		columnVal := reflect.ValueOf(&data).Elem().FieldByName(columnKey)
		if columnVal.IsValid() {
			curNum = int(columnVal.Int())
		}

		//校验是否足量
		if curNum+incNum <= 0 {
			return errors.New("不足扣减")
		}

		//更新数据
		if err := tx.Table("user_val").
			Where(map[string]interface{}{
				"user_id": uid,
			}).UpdateColumn(columnKey, gorm.Expr(columnKey+" + ?", incNum)).
			Error; err != nil {
			return err
		}

		//================== user_val =================//

		//================== user_val_log =================//
		//构造日志模型
		var log *models.UserValLog
		log, err = column.GetValModel(key, uid, owner)
		if err != nil {
			return err
		}

		//插入新纪录
		if err := tx.Create(log).
			Error; err != nil {
			return err
		}
		//================== user_val_log =================//
		return nil
	})

	return models.VU{
		Had:    curNum,
		Obtain: incNum,
	}, err
}

/**
 * @Description: 获取用户信息
 * @receiver dao
 * @param id 用户ID
 * @return *models.UserDetails 用户详情信息
 * @return error 异常信息
 */
func (dao *UserDao) GetUser(id uint64) (*models.UserDetails, error) {

	//用户模型
	var data models.UserDetails
	// 查询数据
	if err := dao.DB.Unscoped().
		Table("user").
		Preload(clause.Associations). //预加载全部关联
		Where("id = ?", id).
		First(&data).
		Error; err != nil {
		//无数据
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		return nil, err
	}

	return &data, nil
}

/**
 * @Description: 获取用户日统计数据
 * @receiver dao
 * @param maps  条件map
 * @return *models.UserDaily 日数据
 * @return error 异常信息
 */
func (dao *UserDao) GetUserDaily(maps map[string]interface{}) (*models.UserDaily, error) {

	var data models.UserDaily
	err := dao.DB.Table("user_std_daily").
		Where(maps).
		First(&data).
		Error

	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}

	return &data, nil
}

/**
 * @Description: 用户收藏
 * @receiver dao
 * @param uid 用户ID
 * @param id 数据ID
 * @param mode 数据类型
 * @return *models.UserAction 收藏
 * @return error 异常信息
 */
func (dao *UserDao) GetUserFav(uid uint64, id uint64, mode string) (*models.UserAction, error) {
	//收藏模型
	var data models.UserAction
	// 查询数据
	if err := dao.DB.Table("user_fav").
		Where("user_id", uid).
		Where("owner_id", id).
		Where("owner_type", mode).
		First(&data).
		Error; err != nil {
		//无数据
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		return nil, err
	}

	return &data, nil
}

/**
 * @Description: 用户赞叹
 * @receiver dao
 * @param uid 用户ID
 * @param id 数据ID
 * @param mode 数据类型
 * @return *models.UserAction 赞叹数据
 * @return error 异常信息
 */
func (dao *UserDao) GetUserPraise(uid uint64, id uint64, mode string) (*models.UserAction, error) {
	//收藏模型
	var data models.UserAction
	// 查询数据
	if err := dao.DB.Table("user_praise").
		Where("user_id", uid).
		Where("owner_id", id).
		Where("owner_type", mode).
		First(&data).
		Error; err != nil {
		//无数据
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		return nil, err
	}

	return &data, nil
}
